package com.test.cordova;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Path;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.media.MediaSyncEvent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.menu.MenuBuilder;
import android.support.v7.widget.Toolbar;
import android.transition.Explode;
import android.transition.Fade;
import android.transition.Slide;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.readystatesoftware.systembartint.SystemBarTintManager;
import com.test.cordova.util.Logger;
import com.test.cordova.util.StatusBarUtil;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试录音
 */

public class AudioRecordActivity extends AppCompatActivity {

    private static final String TAG = AudioRecordActivity.class.getSimpleName();
    private Button bt_stream_recorder,playTask,audioTask;
    private TextView tv_stream_msg;
    private ExecutorService mExecutorService;
    private long startRecorderTime, stopRecorderTime;
    private volatile boolean mIsRecording = false;
    private AudioRecord mAudioRecord;
    private FileOutputStream mFileOutputStream;
    private File mAudioRecordFile;
    private byte[] mBuffer;
    //buffer值不能太大，避免OOM
    private static final int BUFFER_SIZE = 2048;
    private boolean mIsPlaying = false;
    private Handler mHandler = new Handler(Looper.getMainLooper());


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StatusBarUtil.setStatusBarMode(this, false, R.color.deepskyblue);

        setContentView(R.layout.activity_stream);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
            //getWindow().setEnterTransition(new Fade().setDuration(2000));
            //getWindow().setExitTransition(new Fade().setDuration(2000));
            //getWindow().setExitTransition(new Slide().setDuration(2000));
            //getWindow().setEnterTransition(new Slide().setDuration(2000));
            getWindow().setEnterTransition(new Explode().setDuration(2000));
            getWindow().setExitTransition(new Explode().setDuration(2000));
        }



        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("");

        setSupportActionBar(toolbar);
        initView();
        mExecutorService = Executors.newSingleThreadExecutor();
        mBuffer = new byte[BUFFER_SIZE];


    }

    private void initView() {
        bt_stream_recorder = (Button) findViewById(R.id.bt_stream_recorder);
        playTask = (Button) findViewById(R.id.playTask);
        audioTask = (Button) findViewById(R.id.audioTask);
        tv_stream_msg = (TextView) findViewById(R.id.tv_stream_msg);

        audioTask.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startAudioTask();
            }
        });
        playTask.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                playAudioTask();
            }
        });

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            //轨迹动画
            Path path = new Path();
            path.quadTo(0, 300, 150, 150);
            //path.lineTo(100, 300);
            ObjectAnimator animator = ObjectAnimator.ofFloat(tv_stream_msg, View.X, View.Y, path);
            animator.setDuration(3000);
            animator.setInterpolator(new FastOutLinearInInterpolator());
            //animator.setInterpolator(new FastOutSlowInInterpolator());
            //animator.setInterpolator(new LinearOutSlowInInterpolator());
            animator.start();
        }

    }



    private void startAudioTask() {
        if (isRecording) {
            isRecording = false;
            audioTask.setText("audioTask");
            return;
        }
        audioTask.setText("stop");
        //创建录音文件保存路径
        audioFile = new File(Environment.getExternalStorageDirectory(), "audios");
        if (!audioFile.exists()) {
            audioFile.mkdir();
        }
        audioFile = new File(audioFile, System.currentTimeMillis() + ".pcm");

        recordAudio = new RecordAudio();
        recordAudio.execute();

    }

    private void playAudioTask(){
        if (isPlaying) {
            isPlaying = false;
            playTask.setText("playAudio");
            return;
        }
        playTask.setText("stop");

        playAudio = new PlayAudio();
        playAudio.execute();
    }


    private boolean isRecording = false;
    private boolean isPlaying = false;
    private int frequency = 11025;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    int audiosource = MediaRecorder.AudioSource.MIC;
    int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    private File audioFile;
    RecordAudio recordAudio = null;
    PlayAudio playAudio = null;
    private class RecordAudio extends AsyncTask<String,Integer,String>{

        @Override
        protected String doInBackground(String... params) {

            isRecording = true;
            DataOutputStream dos = null;
            try {
                dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));
                int bufferSize = AudioRecord.getMinBufferSize(frequency,channelConfig,audioFormat);
                AudioRecord audioRecord = new AudioRecord(audiosource,frequency,channelConfig,audioFormat,bufferSize);
                short [] buffer = new short[bufferSize];
                audioRecord.startRecording();
                int r = 0;
                while(isRecording){
                    int bufferReadResult = audioRecord.read(buffer,0,bufferSize);
                    Logger.e("RecordAudio: ","isRecording "+bufferReadResult);
                    for (int i = 0; i<bufferReadResult; i++){
                        try {
                            dos.writeShort(buffer[i]);

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    publishProgress(new Integer(r));
                    r++;
                }

                audioRecord.stop();
                dos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            Logger.e("RecordAudio: ","stop");
            super.onPostExecute(s);
        }
    }

    private class PlayAudio extends AsyncTask<Void,Integer,Void>{
        @Override
        protected Void doInBackground(Void... params) {
            isPlaying = true;
            int bufferSize = AudioTrack.getMinBufferSize(frequency,channelConfig,audioFormat);
            short[] buffer = new short[bufferSize / 4];
            DataInputStream dis= null;
            try {
                dis  = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,frequency,channelConfig,audioFormat,bufferSize,AudioTrack.MODE_STREAM);
            audioTrack.play();
            try {
                while(isPlaying && dis.available() > 0 ){
                    Logger.e("PlayAudio: ","isPlaying");
                    int i = 0;
                    while(dis.available() > 0 && i < buffer.length){
                        buffer[i] = dis.readShort();
                        i++;
                    }
                    audioTrack.write(buffer,0,buffer.length);
                }
                dis.close();


            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }


        @Override
        protected void onPostExecute(Void aVoid) {
            playTask.setText("playAudio");
            isPlaying = false;
            Logger.e("PlayAudio: ","stop === " +Thread.currentThread().getName());
            super.onPostExecute(aVoid);
        }
    }

    /**
     * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     */

    public void recorderaudio(View view) {

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            Animator animator2 = ViewAnimationUtils.createCircularReveal(bt_stream_recorder, 0, 0, 0, (float) Math.hypot(bt_stream_recorder.getWidth(), bt_stream_recorder.getHeight()));
            animator2.setDuration(2000);
            animator2.start();
        }

        if (mIsRecording) {
            bt_stream_recorder.setText("开始录音");
            //在开始录音中如果这个值没有变false，则一直进行，当再次点击变false时，录音才停止
            mIsRecording = false;

            //执行停止录音逻辑，这块不用下面代码，只需上面变换mIsRecording这个状态就可以了，下面一直走while
          /*  mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    stopRecorder();
                }
            });*/
        } else {

            bt_stream_recorder.setText("停止录音");
            //提交后台任务，执行录音逻辑
            mIsRecording = true;
            //提交后台任务，执行录音逻辑
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {

                    startRecorder();
                }
            });
        }
    }

    /**
     * 开始录音
     */
    private void startRecorder() {
        // realeseRecorder();
        if (!dostart()) recorderFail();

    }

    /**
     * 停止录音
     */
    private void stopRecorder() {
        mIsRecording = false;
        if (!doStop()) recorderFail();

    }


    private boolean dostart() {
        try {

            //创建录音文件
            mAudioRecordFile = new File(Environment.getExternalStorageDirectory(), "recorderdemo");
            if (!mAudioRecordFile.exists()) {
                mAudioRecordFile.mkdir();
            }
            //记录开始录音时间
            startRecorderTime = System.currentTimeMillis();
            mAudioRecordFile = new File(mAudioRecordFile, System.currentTimeMillis() + ".pcm");
            //mAudioRecordFile.createNewFile();
            Logger.e(TAG, " getParentFile: " + mAudioRecordFile.getParentFile() + " getParentFile: " + mAudioRecordFile.getParentFile().exists() + " mAudioRecordFile.getAbsolutePath()  " + mAudioRecordFile.getAbsolutePath() + " mAudioRecordFile " + mAudioRecordFile.exists());
            //创建文件输出流
            mFileOutputStream = new FileOutputStream(mAudioRecordFile);

            setAudioRecord();

            if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
                //未初始化成功 无法开启录音
                return false;
            }
            //开始录音
            mAudioRecord.startRecording();

            //循环读取数据，写入输出流中
            while (mIsRecording) {
                //只要还在录音就一直读取
                int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
                int i = calculateVolume(mBuffer, 16);
                Logger.e(TAG, " calculateVolume " + i);
                if (i != 0) {
                    if (read <= 0) {
                        return false;
                    } else {
                        mFileOutputStream.write(mBuffer, 0, read);
                    }
                }
            }

            //退出循环，停止录音，释放资源
            stopRecorder();

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (mAudioRecord != null) {
                mAudioRecord.release();
            }
        }
        return true;
    }

    private void setAudioRecord() {
        //配置AudioRecord
        int audioSource = MediaRecorder.AudioSource.MIC;
        //所有android系统都支持
        int sampleRate = 44100;
        //单声道输入
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        //PCM_16是所有android系统都支持的
        int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
        //计算AudioRecord内部buffer最小
        int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
        //buffer不能小于最低要求，也不能小于我们每次我们读取的大小。
        mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
    }


    public int calculateVolume(byte[] datas, int format) {
        int[] var3 = null;
        int var4 = datas.length;
        int var2;
        if (format == 8) {
            var3 = new int[var4];
            for (var2 = 0; var2 < var4; ++var2) {
                var3[var2] = datas[var2];
            }
        } else if (format == 16) {
            var3 = new int[var4 / 2];
            for (var2 = 0; var2 < var4 / 2; ++var2) {
                byte var5 = datas[var2 * 2];
                byte var6 = datas[var2 * 2 + 1];
                int var13;
                if (var5 < 0) {
                    var13 = var5 + 256;
                } else {
                    var13 = var5;
                }
                short var7 = (short) (var13 + 0);
                if (var6 < 0) {
                    var13 = var6 + 256;
                } else {
                    var13 = var6;
                }
                var3[var2] = (short) (var7 + (var13 << 8));
            }
        }

        int[] var8 = var3;
        if (var3 != null && var3.length != 0) {
            float var10 = 0.0F;
            for (int var11 = 0; var11 < var8.length; ++var11) {
                var10 += (float) (var8[var11] * var8[var11]);
            }
            var10 /= (float) var8.length;
            float var12 = 0.0F;
            for (var4 = 0; var4 < var8.length; ++var4) {
                var12 += (float) var8[var4];
            }
            var12 /= (float) var8.length;
            var4 = (int) (Math.pow(2.0D, (double) (format - 1)) - 1.0D);
            double var14 = Math.sqrt((double) (var10 - var12 * var12));
            int var9;
            if ((var9 = (int) (10.0D * Math.log10(var14 * 10.0D * Math.sqrt(2.0D) / (double) var4 + 1.0D))) < 0) {
                var9 = 0;
            }
            if (var9 > 10) {
                var9 = 10;
            }
            return var9;
        } else {
            return 0;
        }
    }


    private boolean recorderFail() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                bt_stream_recorder.setText("开始录音");
                tv_stream_msg.setText("录取失败，请重新录入");

                mIsRecording = false;
                Logger.i(TAG, "录取失败");
            }
        });

        return false;
    }

    private void realeseRecorder() {
        mAudioRecord.release();
    }

    private boolean doStop() {
        //停止录音，关闭文件输出流
        mAudioRecord.stop();
        mAudioRecord.release();
        mAudioRecord = null;
        //记录结束时间，统计录音时长
        stopRecorderTime = System.currentTimeMillis();
        //大于3秒算成功，在主线程更新UI
        final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
        if (send > 3) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    tv_stream_msg.setText("录音成功：" + send + "秒");
                    bt_stream_recorder.setText("开始录音");
                    Logger.i(TAG, "开始录音");
                }
            });
        } else {
            recorderFail();
            return false;
        }
        return true;
    }

    /**
     * 播放声音
     *
     * @param view
     */
    public void player(View view) {
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                if (!mIsPlaying) {
                    Logger.i(TAG, "播放声音");
                    mIsPlaying = true;
                    doPlay(mAudioRecordFile);
                }

            }
        });
    }

    private void doPlay(File audioFile) {
        if (audioFile != null) {
            //配置播放器
            //音乐类型，扬声器播放
            int streamType = AudioManager.STREAM_MUSIC;
            //录音时采用的采样频率，所以播放时同样的采样频率
            int sampleRate = 44100;
            //单声道，和录音时设置的一样
            int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
            //录音时使用16bit，所以播放时同样采用该方式
            int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
            //流模式
            int mode = AudioTrack.MODE_STREAM;

            //计算最小buffer大小
            int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);

            //构造AudioTrack  不能小于AudioTrack的最低要求，也不能小于我们每次读的大小
            AudioTrack audioTrack = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat,
                    Math.max(minBufferSize, BUFFER_SIZE), mode);
            audioTrack.play();
            //从文件流读数据
            FileInputStream inputStream = null;
            try {
                //循环读数据，写到播放器去播放
                inputStream = new FileInputStream(audioFile);

                //循环读数据，写到播放器去播放

                int read;
                //只要没读完，循环播放
                while ((read = inputStream.read(mBuffer)) > 0) {
                    int ret = audioTrack.write(mBuffer, 0, read);
                    Logger.i(TAG, "doPlay read:" + read + " audioTrack.write: " + ret + " calculateVolume: " + calculateVolume(mBuffer, 16));
                    //检查write的返回值，处理错误
                    switch (ret) {
                        case AudioTrack.ERROR_INVALID_OPERATION:
                        case AudioTrack.ERROR_BAD_VALUE:
                        case AudioManager.ERROR_DEAD_OBJECT:
                            playFail();
                            return;
                        default:
                            break;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                //读取失败
                playFail();
            } finally {
                mIsPlaying = false;
                //关闭文件输入流
                if (inputStream != null) {
                    closeStream(inputStream);
                }
                //播放器释放
                resetQuietly(audioTrack);
            }

            //循环读数据，写到播放器去播放
            //错误处理，防止闪退

        }
    }

    /**
     * 关闭输入流
     *
     * @param inputStream
     */
    private void closeStream(FileInputStream inputStream) {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void resetQuietly(AudioTrack audioTrack) {
        try {
            audioTrack.stop();
            audioTrack.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 播放失败
     */
    private void playFail() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                tv_stream_msg.setText("播放失败");
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mExecutorService != null) {
            mExecutorService.shutdownNow();
        }
        if (mAudioRecord != null) {
            mAudioRecord.stop();
            mAudioRecord.release();
            mAudioRecord = null;
        }
    }

}
